iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 10
1
Modern Web

小白的JavaScript讀書日記系列 第 10

Day10:操作HTML (一)

  • 分享至 

  • xImage
  •  

DOM

在開始操作前,我們需要先了解DOM是什麼

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My title</title>
</head>

<body>
  <h1>My header</h1>
    <a href="">My link</a>
</body>

</html>

上述這段html程式碼,可以對照以下的圖片:
https://ithelp.ithome.com.tw/upload/images/20200909/20129488yAeufTkRym.png

DOM=Document Object Model
文件中包含的元素,屬性,文字都被視為物件,所以是一個物件集合的文件檔案。
而構成文件的有:

  • Element 元素
  • Attribute 屬性
  • Text 文字
    上述三種被稱之為節點(Node),對應其種類分別有元素節點、屬性節點和文字節點,
    DOM就是針對這些節點提供取出,新增,刪除,取代,等操作的API(Application Programming Interface)
    節點在樹狀圖上皆有相互關係,請看下圖:
    https://ithelp.ithome.com.tw/upload/images/20200909/201294884r9xmjmust.png
    藍色框框內的兩個元素節點:兄弟關係。
    紅色框框內的元素節點(父)和文字節點(子):父子關係。

取得元素節點

如上述所說,我們知道了DOM裡面有節點,要操作前,我們必須先將元素節點取出,才可以操作。下面介紹幾種取得元素節點的方法,詳細請參照w3c裡面的解說及案例。
https://www.w3schools.com/js/js_htmldom_elements.asp

  • 以id為鍵取得元素 - getElementById
    語法:document.getElementById(id); id:欲取得的元素id。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My title</title>
</head>
<body>
  <span id="result">Now:</span>
  <!--得到  2020/9/9 下午5:01:07 -->

  <script>
    //建立時間日期
    let current = new Date();

    //取得具有該id的元素並回傳(d="result"),且賦值給變數result
    let result = document.getElementById('result');

    //將取的的元素用textContent插入上面宣告的變數current
    result.textContent = current.toLocaleString();
  </script>
</body>
</html>

這邊要注意的是如果id重複,getElementByID會回傳第一個符合的元素。

  • querySelectorAll
    將較於getXXXX,queryXXXX可以搜尋更複雜的條件搜尋,這方法必須配合選擇器(HTML),請參照以下w3c
    https://www.w3schools.com/css/css_selectors.asp
    這種寫法可以簡化複雜的程式,例如:在id="xxx"下找出class="yyy"的元素,就可以簡化成#xxx .yyy
    語法:document.querySelectorAll('xxx')
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My title</title>
</head>
<body>
  <ul id="list">
    <li><a href="https://tw.yahoo.com/" class="ya">Yahoo</a></li>
    <li><a href="https://www.google.com/?hl=zh_tw" class="gg">Google</a></li>
    <li><a href="https://shopping.pchome.com.tw/" class="gg">PChome</a></li>
  </ul>

  <script>
    //取出符合id="list" 且 class="gg"的全部元素節點,並用for 在console印出來
    let list = document.querySelectorAll('#list .gg');
    for (var i = 0, len = list.length; i < len; i++) {
      console.log(list.item(i).href);
    }
    //結果:https://www.google.com/?hl=zh_tw
    //     https://shopping.pchome.com.tw/
  </script>
</body>

</html>

上面介紹的getElementById、querySelectorAll在文件裡面還有getElementByXXX以及querySelector..等可以把元素取出來的方法;
對照起來是getElement/getElementByxxxx 對比 querySelector/querySelectorAll
兩種方法比較起來是getElementBy的方法速度較快,實作上面我自己是用querySelector比較多,寫起來比較直觀。

尋訪文件樹

上述介紹的getElementById和querySelectorAll,這些方法都會以精確的定位取得元素,但效能不佳,原因是當這些方法在找元素的時候,會整個文件逐一搜尋。
因此DOM提供了另一種方法,以某個節點為出發點,透過位置的相對關係取得節點,這種方式與getxxxx/querySelector比較,程式碼會較為為冗長。
在實作上通常搭配使用,先用getxxxx/querySelector尋得特定元素後,再用節點尋訪的方式找到鄰近的節點。

節點與節點的關係大致上可以分層兩種,就是上述提到的父子、兄弟關係:

  • 父子關係:除了document之外,每一個節點都會有個上層的節點,稱為父節點(Parent node),而父節點的下層,稱為子節點(Child node)。
  • 兄弟關係:有同一個父節點的關係,他們彼此就是兄弟節點(Siblings node)。
    p.s.可以透過藍框框和紅框框再觀察一下。

當我們了解了他們的關係後,接著我們透過程式碼來解釋:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
<form>
    <label for="food">你最喜歡的食物</label>
    <select id="food">
<option value="麥當勞">麥當勞</option>
<option value="肯德基">肯德基</option>
<option value="丹丹">丹丹</option>
    </select>
</form>

    <script>
        //先取得id="food"的元素節點
        let s =document.getElementById('food');

        //用childNode去找id="food"節點下的子節點
        let opts =s.childNodes;

        //這邊我們得到 NodeList(7) [text, option, text, option, text, option, text],可以發現childNodes不只有本身的屬性會抓到外,也會抓到元素節點,以及字串節點。
        console.log(opts);

        //用for依序取得子節點,並在for裡面用nodeType判斷是否為元素,是的話才在console印出對應的值。
        for (let i = 0,len=opts.length;i<len;i++){
            let opt = opts.item(i);
            if(opt.nodeType ===1){
                console.log(opt.value);
            }
        }
        //結果得到:
        //麥當勞
        //肯德基
        //丹丹
    </script>
</body>
</html>

透過上述例子我們可以發現,getElementById與childNode的搭配使用。
另外要特別補充的是nodeType,當我們要判斷節點類型時可以用nodeType判斷,下列網址有彙整nodeType屬性的回傳值:
(我們在上述的例子就是用回傳值1來判斷是否為元素節點。)
https://www.w3schools.com/jsref/prop_node_nodetype.asp

firstElementChild / nextElementSibling

這邊用這兩個屬性來改寫一下上述的例子,使用這兩個屬性會直接抓到對應的元素,因此不用nodeType來判斷是否為元素,請看下列改寫的程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
<form>
    <label for="food">你最喜歡的食物</label>
    <select id="food">
<option value="麥當勞">麥當勞</option>
<option value="肯德基">肯德基</option>
<option value="丹丹">丹丹</option>
    </select>
</form>

    <script>
        //先取得id="food"的元素節點
        let s =document.getElementById('food');

        //取得id="food"元素的第一個子元素
        let child = s.firstElementChild;

        //當子節點存在時以迴圈再console印出
        while(child){
            console.log(child.value);
            child = child.nextElementSibling;
        }
    </script>
</body>
</html>

再上述程式碼中,結果與未改寫前相同,但我們省略nodeType去判斷是否為元素。
可以試看看,比較看看!



今日總結

  • 什麼是DOM
  • 如何取的元素節點(getXXXXXX/querySelect)
  • 節點尋訪

今天程式碼的篇幅有點長,但我覺得透過例子比較能理解今天的內容,
這邊在附上w3c中各種取得節點,尋訪節點的屬性及方法,以便參考裡面的例子,更加深元素節點的概念。(太多了,要一一介紹實在是講不完Q_Q)
https://www.w3schools.com/JSREF/dom_obj_all.asp

不得不說有w3c真的是太棒了!雖然是英文,但對比書本上的例子,再網站中的例子更為豐富以及實用!今天就沒有練習了,我自己是透過w3c中的練習來加強印象。
我們明天繼續!


上一篇
Day9:中場murmur
下一篇
Day11:操作HTML (二)
系列文
小白的JavaScript讀書日記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言